package com.authine.cloudpivot.engine.service.runtime;

import com.authine.cloudpivot.engine.api.model.bizservice.ParameterModel;
import com.authine.cloudpivot.engine.api.model.runtime.BizObjectModel;
import com.authine.cloudpivot.engine.api.model.runtime.SelectionValue;
import com.authine.cloudpivot.engine.component.query.api.FilterExpression;
import com.authine.cloudpivot.engine.component.query.api.Page;
import com.authine.cloudpivot.engine.domain.bizmodel.BizProperty;
import com.authine.cloudpivot.engine.domain.bizmodel.Mapping;
import com.authine.cloudpivot.engine.domain.bizmodel.Quote;
import com.authine.cloudpivot.engine.domain.runtime.BizAttachment;
import com.authine.cloudpivot.engine.domain.runtime.BizComment;
import com.authine.cloudpivot.engine.domain.runtime.BizObject;
import com.authine.cloudpivot.engine.domain.runtime.Comment;
import com.authine.cloudpivot.engine.enums.type.BizPropertyType;
import com.authine.cloudpivot.engine.enums.type.bizrule.DefaultBusinessRuleType;
import com.authine.cloudpivot.foundation.orm.api.model.BizObjectQueryObject;
import com.authine.cloudpivot.foundation.orm.api.model.QueryRelationObject;
import org.apache.commons.lang3.tuple.Pair;

import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 业务对象相关数据转换器.
 */
public interface BizObjectConverter {
    /**
     * 将业务对象数据转换为集成方法参数.
     *
     * @param bizObject  业务对象
     * @param parameters 入参列表
     * @param mappings   数据映射列表
     * @return 集成方法参数对象
     */
    Map<String, Object> toArgs(BizObject bizObject, List<ParameterModel> parameters, List<Mapping> mappings);

    /**
     * 将动态查询对象转换为集成方法参数.
     *
     * @param bizObjectQueryObject 动态查询对象
     * @param parameters           入参列表
     * @param mappings             数据映射列表
     * @return 集成方法参数对象
     */
    Map<String, Object> toArgs(BizObjectQueryObject bizObjectQueryObject, List<ParameterModel> parameters, List<Mapping> mappings);

    /**
     * 将集成方法返回的单值对象转换为Map.
     *
     * @param returnObject 集成方法返回的单值对象转
     * @param parameters   出参列表
     * @param mappings     数据映射列表
     * @return Map
     */
    Map<String, Object> fromSingleReturn(Object returnObject, List<ParameterModel> parameters, List<Mapping> mappings);

    /**
     * 将集成方法返回的集合对象转换为Page.
     *
     * @param returnObject 集成方法返回的集合对象
     * @param parameters   出参列表
     * @param mappings     数据映射列表
     * @return Page
     */
    Page fromListReturn(Object returnObject, List<ParameterModel> parameters, List<Mapping> mappings);


    /**
     * 从外部输入转换值.
     * <p>
     * 宽进严出原则.
     *
     * @param value       外部输入值
     * @param bizProperty 数据项
     */
    Object fromFormValue(@Nullable Object value, BizProperty bizProperty);

    /**
     * 从外部输入转换值
     * @param value
     * @param bizProperty
     * @return
     */
    Object fromInputValue(@Nullable Object value, BizProperty bizProperty);

    /**
     * 从外部输入转换值.
     * <p>
     * 宽进严出原则.
     *
     * @param value       外部输入值
     * @param code 数据项
     */
    String fromFormSelectionValue(@Nullable String code, Object value);

    /**
     * 从外部输入转换值为boolean类型.
     * <p>
     * 宽进严出原则.
     *
     * @param value 外部输入值
     */
    Boolean fromFormLogicValue(@Nullable Object value);

    /**
     * 批量转换来自数据库的值.
     * <p>
     * 宽进严出原则.
     */
    List<Map<String, Object>> fromDbValues(List<Map<String, Object>> dataList, BizPropertyMap bpMap);

    /**
     * 批量转换来自数据库的值.
     * <p>
     * 宽进严出原则.
     */
    List<Map<String, Object>> fromDbIgoValues(List<Map<String, Object>> dataList, BizPropertyMap bpMap);

    Object fromQuoteValue(@Nullable final Object value, final BizProperty bizProperty);

    /**
     * 转换来自数据库的值.
     **/
    Map<String, Object> fromDbValues(Map<String, Object> data, BizPropertyMap bpMap);

    Map<String, Object> fromDbValues(Map<String, Object> data, BizPropertyMap bpMap, boolean needDisplayField);

    Object fromDbValue(@Nullable final Object value, final BizProperty bizProperty);

    /**
     * 转换来自数据库的值.（忽略关联表单）
     **/
    Map<String, Object> fromDbIgoValues(Map<String, Object> data, BizPropertyMap bpMap);

    /**
     * 转换数据库中选人控件的值.
     */
    List<SelectionValue> fromDbSelectionValue(@Nullable String code, @Nullable Object value,
                                              BizPropertyType bizPropertyType);

    List<SelectionValue> getUserSelections(List<String> userIds);

    /**
     * 转换数据库中子表的值.
     *
     * @param code     子表数据项code
     * @param objectId 主表记录id
     */
    List<Map<String, Object>> fromDbChildTableValue(String code, String objectId, boolean withResources);
    List<Map<String, Object>> fromDbChildTableValue(String code, String objectId);
    Pair<List<Map<String, Object>>, Map<String, Map<String, Object>>> fromDbChildTableValue(String code, List<String> objectIds, boolean childPageEnable, int pageSize);

    /**
     *
     * 格式话数据库返回数据
     * @param  data          数据库返回数据
     * @param  bizProperties 数据项信息
     * @return               格式化后数据
     **/
    List<Map<String, Object>> formatDbData(List<Map<String, Object>> data, List<BizProperty> bizProperties);

    /**
     * 批量转换数据库中子表的值.
     *
     * @param code     子表数据项code
     * @param
     */
    List<Map<String, Object>> fromDbChildTableValues(String code,  boolean withResources);


    /**
     * 批量转换资源信息.
     */
    List<Map<String, Object>> fromDbAttachments(List<BizAttachment> bizAttachments);

    /**
     * 转换数据库中附件的值.
     *
     * @param schemaCode   业务模型编码
     * @param objectId     业务对象id
     * @param propertyCode 数据项code
     * @param objectId     主表记录id
     */
    List<Map<String, Object>> fromDbAttachments(String schemaCode, String objectId, String propertyCode);

    /**
     * 批量转换审批意见.
     */
    List<Comment> fromDbComments(List<BizComment> bizComments);

    /**
     * api : 关联表单显示字段引用链
     * @param schemaCode
     * @param workSheetCode
     * @param relativePropertyCode
     * @return
     */
    Map<String, List<Quote>> parseQuote(String schemaCode, String workSheetCode, String relativePropertyCode);


    Map<String, Object> fromQuoteWorkSheetValue(final Object value, final BizProperty bizProperty);

    /**
     * 将数据库查询结果转换为数据项类型结果
     * @param dataList
     * @param queryRelationObject
     * @param bizPropertyMap
     * @return
     */
    List<Map<String, Object>> fromDbValues(List<Map<String, Object>> dataList, QueryRelationObject queryRelationObject, Map<String, BizProperty> bizPropertyMap);

    /**
     * 查询关联表单数据
     *
     * @param schemaCode        模型编码
     * @param objectIds         待查询的数据id
     * @param displayFieldCode  展示字段的数据项编码
     * @param propertyType      数据项类型
     * @return List
     */
    List<Map<String, Object>> queryWorkSheetData(String schemaCode, List<String> objectIds, String displayFieldCode, BizPropertyType propertyType);

    /**
     * in分批查询，oracle 1000，其他数据库2000
     * @return int
     **/
    int getDbQueryPerMaxNum();

    /**
     *
     * 处理主表关联单选
     * @param   workSheetFields    关联单选、关联多选字段
     * @param   bpMap              数据项
     * @param   mainTableDataMap   主表字段
     **/
    void dealMainWorkSheets(Set<String> workSheetFields, BizPropertyMap bpMap, Map<String, Map<String, Object>> mainTableDataMap);

    /**
     * 义务集成数据结果处理
     * @param object       待处理数据
     * @param schemaCode  模型编码
     * @return List
     **/
    Object dealBizMethodData(Object object, String schemaCode);

    /**
     *
     * 查询 业务规则 数据源类型
     * @param  schemaCode        模型编码
     * @param  businessRuleType  规则编码
     * @return boolean
     **/
    boolean businessRuleIsBizAction(String schemaCode, DefaultBusinessRuleType businessRuleType);
    /**
     *
     * 根据数据id查询模型对于数据是否存在
     * @param  schemaCode 模型编码
     * @param  ids        数据ID
     * @return Map
     **/
    Map<Boolean, Set<String>> checkDataExist(String schemaCode, List<String> ids);

    BizObject queryRelationData(String schemaCode, String objectId);

    int getTreeMaxDepth();


    /**
     *
     * 树形模型-节 查询点数据
     * @param bizObjectQueryObject 列表查询调剂
     * @param bizProperties        数据项值
     * @param content              第一次查询的列表数据
     * @param parentRefFieldCode       所用的关联字段编码
     * @return List
     **/
     List<Map<String, Object>> queryTreeData (BizObjectQueryObject bizObjectQueryObject, List<Map<String, Object>> content,
                                                     List<BizProperty> bizProperties, String parentRefFieldCode);

    /**
     *
     * 树形模型-列表展示时-构建path
     * @param schemaCode            模型编码
     * @param content               待处理数据
     * @param bizProperties         数据项
     * @param bizPropertyParentRef  用于关联的数据项
     **/
    void buildTreePath(String schemaCode, List<Map<String, Object>> content, List<BizProperty> bizProperties, BizProperty bizPropertyParentRef);

    /**
     *
     * 数据模型-数据转换为数结构
     * @param  content                列表数据
     * @param  parentRefValue         所属父节点标识
     * @param  parentRefFieldCode     所使用的父子关联字段
     * @param  showPath               是否展示路径
     * @param  displayFiledCode       展示字段编码
     * @return List
     **/
    List<Map<String, Object>> buildTreeChildData (List<Map<String, Object>> content, String parentRefValue, String parentRefFieldCode, boolean showPath, String displayFiledCode);

    /**
     *
     * 树形模型-校验循环引用
     * @param bizObject       当前对象
     * @param bizProperties   数据项
     **/
    void checkTreeCircularRef(BizObject bizObject,  List<BizProperty> bizProperties);

    /**
     *
     * 树形模型-批量插入-校验循环引用（目前只有导入数据会触发）
     * @param data            导入的数据
     * @param schemaCode      模型编码
     * @return void
     **/
    List<Map<String, Object>> batchCheckTreeCircularRef(List<Map<String, Object>> data, String schemaCode);

    /**
     *
     * 树形模型-删除时校验该数据是否存在子节点
     * @param schemaCode   模型编码
     * @param objectIds    待校验数据id
     * @return boolean
     **/
    boolean checkTreeExistChild(String schemaCode,  List<String> objectIds);

    /**
     *
     * 树形模型-新增时-构建path
     * @param bizObject        bo数据
     * @param bizProperties    数据项信息
     * @return BizObject
     **/
    BizObject buildBizObjectTreePath(BizObject bizObject, List<BizProperty> bizProperties);

    /**
     *
     * 树形模型-修改时-变更子数据path
     * @param bizObject        bo数据
     * @param bizProperties    数据项信息
     *
     **/
    void updateTreeChildPath(BizObject bizObject, List<BizProperty> bizProperties);

    /**
     *
     * 获取所有父节点ID
     *
     * @param schemaCode 模型编码
     * @param objectId   数据ID
     * @return List
     **/
    List<String> getAllTreeParentIds(String schemaCode, String objectId);

    /**
     *
     * 判断父级阶段 是否有权限查看
     *
     * @param bizObjectQueryObject 查询条件
     * @param parentRef            数据ID
     * @return boolean
     **/
    boolean judgeTreeParentDataAuth (BizObjectQueryObject bizObjectQueryObject, String parentRef);

    /**
     *
     * 树形模型 获取用户有权查看的顶点所属层级
     *
     * @param bizObjectQueryObject 查询条件
     * @param properties           数据项
     * @return Integer
     **/
    Integer getTreeTopDataLevel(BizObjectQueryObject bizObjectQueryObject, List<BizProperty> properties);

    /**
     *
     * 树形模型 获取用户有权查看的顶点数据路径 组装成查询条件
     *
     * @param bizObjectQueryObject 查询条件
     * @param level                顶点层级
     * @return Integer
     **/
    Pair<String, FilterExpression> getTreeTopDataPathFilter(BizObjectQueryObject bizObjectQueryObject, Integer level);

    /**
     *
     * 执行计算规则
     *
     * @param bizObject   bo数据
     * @return BizObject
     **/
    BizObject executeCalculateRule(BizObject bizObject);

    /**
     *
     * 执行计算规则
     *
     * @param bizObject        bo数据
     * @param executeCalRule   true 强制执行所有计算规则 false 当前数据项为空时，才计算规则
     * @return BizObject
     **/
    BizObject executeCalculateRule(BizObject bizObject, boolean executeCalRule);

    /**
     * 根据子表编码与查询条件查询子表数据
     * @param code 子表编码
     * @param bizObjectQueryObject 查询对象
     * @return
     */
    List<Map<String, Object>> findChildTableData(String code, BizObjectQueryObject bizObjectQueryObject);

    /**
     * 从数据库获取子表数据，合并（计算规则使用）
     * @param bizObjectModel 业务数据
     * @param subSchemaCode  子表编码
     * @param propertyCode   数据项编码
     * @return               数据
     */
    List<Object> margeChildDataFromDb(BizObjectModel bizObjectModel, String subSchemaCode, String propertyCode);


    /**
     *
     * @param userId 用户id
     * @return 封装用户信息
     */
    SelectionValue getIdToSelectionValue(String userId);

    List<String> completeSystemFields(String schemaCode, Map<String, Object> quotes, List<String> columnList);
}
